package com.inspection.service.impl;

import com.google.common.collect.Lists;
import com.inspection.config.LoginConstant;
import com.inspection.constant.UserStatusEnum;
import com.inspection.constant.YesNoEnum;
import com.inspection.dao.InspectionDepartmentDao;
import com.inspection.dao.SysUserDao;
import com.inspection.dao.SysUserRoleDao;
import com.inspection.entity.*;
import com.inspection.model.dto.InspectionRegulationDTO;
import com.inspection.model.dto.SysConfigQueryDTO;
import com.inspection.model.dto.SysUserDTO;
import com.inspection.model.dto.SysUserQueryDTO;
import com.inspection.model.excel.SysUserExcelVO;
import com.inspection.service.SysUserService;
import com.inspection.support.AssertUtils;
import com.inspection.support.ExcelUtils;
import com.inspection.support.PageHelper;
import com.inspection.support.SortHelper;
import com.inspection.support.auth.AuthHolder;
import com.inspection.support.model.BusinessBaseException;
import com.inspection.support.model.KeyValuePair;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class SysUserServiceImpl implements SysUserService {
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    @Autowired
    private InspectionDepartmentDao inspectionDepartmentDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(SysUserDTO user) {

        AssertUtils.nonNull(user.getUserName(), "登录账号不能为空");
        AssertUtils.nonNull(user.getPassword(), "密码不能为空");
        AssertUtils.nonNull(user.getConfirmPassword(), "确认密码不能为空");
        AssertUtils.nonNull(user.getUserCode(), "用户编码不能为空");

        if (!user.getConfirmPassword().equals(user.getPassword())) {
            throw new BusinessBaseException("请确认两次输入的密码是否一致！");
        }
        //部门拦截一道
        if (!StringUtils.isEmpty(user.getDeptId())) {
            Optional<InspectionDepartmentDO> dept = inspectionDepartmentDao.findById(user.getDeptId());
            if (!dept.isPresent()) {
                throw new BusinessBaseException("部门信息不存在");
            }
            if (!dept.get().getIsLeafNode().equals(YesNoEnum.YES.getVal())) {
                throw new BusinessBaseException("请选择实际的部门[非目录]") ;
            }
        }

        Specification<SysUserDO> specification = (Specification<SysUserDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.equal(root.get("isDel"), 0));

            predicates.add(criteriaBuilder.or(
                    criteriaBuilder.equal(root.get("userName"), user.getUserName()),
                    criteriaBuilder.equal(root.get("userCode"), user.getUserCode())));

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        Optional<SysUserDO> sysUserOp = sysUserDao.findOne(specification);
        if(sysUserOp.isPresent()){
            throw new BusinessBaseException("已存在登录名/用户编码 的用户！");
        }



        SysUserDO sysUser = new SysUserDO();
        BeanUtils.copyProperties(user, sysUser);
        sysUser.setPassword(DigestUtils.md5Hex(user.getPassword()+ LoginConstant.LOGIN_SALT));
       // sysUser.setUserStatus(UserStatusEnum.NORMAL.getStatus());
        sysUser.setIsDel(0);
        sysUser.setDateCreate(new Date());
        sysUserDao.saveAndFlush(sysUser);

        //新增用户-角色
        if (!CollectionUtils.isEmpty(user.getRoleIdList())) {

            for (Long roleId : user.getRoleIdList()) {
                SysUserRoleDO userRole = new SysUserRoleDO();
                userRole.setUserId(sysUser.getId());
                userRole.setRoleId(roleId);
                sysUserRoleDao.saveAndFlush(userRole);
            }

        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(SysUserDTO user) {

        AssertUtils.nonNull(user.getId(), "系統用戶id不能為空！");

//        SysUserDO sysUser = AuthHolder.getSysUser();
//        Boolean isSysAdmin = false;
//        if ("00000".equalsIgnoreCase(sysUser.getUserCode())) {
//            isSysAdmin = true;
//        }
//        if (!isSysAdmin && !user.getId().equals(sysUser.getId())) {
//            throw new BusinessBaseException("沒有權限修改其他用戶！");
//        }

        Optional<SysUserDO> sysUserOp = sysUserDao.findById(user.getId());
        if (!sysUserOp.isPresent()) {
            throw new BusinessBaseException("用戶不存在");
        }
        //除非是超管本人 其他人不允许修改超管
        SysUserDO sysUser = AuthHolder.getSysUser();
        if ("00000".equals(sysUserOp.get().getUserCode()) && !"00000".equals(sysUser.getUserCode())) {
            throw new BusinessBaseException("超管账户只允许超管本人修改");
        }

        //如果部门发生了修改 就需要对新修改的部门进行合法性校验
        if (Objects.nonNull(sysUserOp.get().getDeptId()) && Objects.nonNull(user.getDeptId())
                && !user.getDeptId().equals(sysUserOp.get().getDeptId())) {
            Optional<InspectionDepartmentDO> updateDept = inspectionDepartmentDao.findById(user.getDeptId());
            if (!updateDept.isPresent()) {
                throw new BusinessBaseException("部门信息不存在");
            }
            if (!updateDept.get().getIsLeafNode().equals(YesNoEnum.YES.getVal())) {
                throw new BusinessBaseException("请选择实际的部门[非目录]");
            }
        }


        
        //如果登录名和编号发生修改 需要判断是否重复
        if (!sysUserOp.get().getUserName().equals(user.getUserName()) || !sysUserOp.get().getUserCode().equals(user.getUserCode())) {
            Specification<SysUserDO> specification = (Specification<SysUserDO>) (root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = Lists.newArrayList();
                predicates.add(criteriaBuilder.equal(root.get("isDel"), 0));

                predicates.add(criteriaBuilder.or(
                        criteriaBuilder.equal(root.get("userName"), user.getUserName()),
                        criteriaBuilder.equal(root.get("userCode"), user.getUserCode())));

                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            };
            List<SysUserDO> users = sysUserDao.findAll(specification);
            if (!CollectionUtils.isEmpty(users)) {
                //修改自己是可以的 但是跟别人重复不行
                if(users.size()>1||!users.get(0).getId().equals(sysUserOp.get().getId())){
                    //肯定冲突了
                    throw new BusinessBaseException("您要修改的登录名/用户编码已被其他人使用");
                }

            }
        }



        SysUserDO userUpdate = sysUserOp.get();
        if (Objects.nonNull(user.getPassword())) {
            //有修改密碼
            if (!user.getConfirmPassword().equals(user.getPassword())) {
                throw new BusinessBaseException("请确认两次输入的密码是否一致！");
            }
            userUpdate.setPassword(DigestUtils.md5Hex(user.getPassword()+LoginConstant.LOGIN_SALT));
        }
        //區分admin 和其他用戶 只有admin才可以修改一些敏感信息

        userUpdate.setUserCode(user.getUserCode());
        userUpdate.setUserName(user.getUserName());
        userUpdate.setMobile(user.getMobile());
        userUpdate.setRealName(user.getRealName());
        userUpdate.setWorkPhone(user.getWorkPhone());
        userUpdate.setEmail(user.getEmail());
        userUpdate.setDeptId(user.getDeptId());
        userUpdate.setUserStatus(user.getUserStatus());
        sysUserDao.saveAndFlush(userUpdate);

        //更新角色
        SysUserRoleDO userRoleQuery = new SysUserRoleDO();
        userRoleQuery.setUserId(userUpdate.getId());
        List<SysUserRoleDO> userRoles = sysUserRoleDao.findAll(Example.of(userRoleQuery));
        if (!CollectionUtils.isEmpty(userRoles)) {
            sysUserRoleDao.deleteInBatch(userRoles);
        }

        //新增用户-角色
        if (!CollectionUtils.isEmpty(user.getRoleIdList())) {

            for (Long roleId : user.getRoleIdList()) {
                SysUserRoleDO userRole = new SysUserRoleDO();
                userRole.setUserId(userUpdate.getId());
                userRole.setRoleId(roleId);
                sysUserRoleDao.saveAndFlush(userRole);
            }

        }

    }

    @Override
    public SysUserDO getUser(SysUserQueryDTO query) {
        SysUserDO sysUser = AuthHolder.getSysUser();
//        Boolean isSysAdmin = false;
//        if ("00000".equalsIgnoreCase(sysUser.getUserCode())) {
//            isSysAdmin = true;
//        }
//        if (!isSysAdmin && !query.getId().equals(sysUser.getId())) {
//            throw new BusinessBaseException("沒有权限修改其他用戶信息！");
//        }


        Optional<SysUserDO> sysUserOp = sysUserDao.findById(query.getId());
        if (!sysUserOp.isPresent()) {
            throw new BusinessBaseException("用戶不存在");
        }
        SysUserDO user = sysUserOp.get();

        if(Objects.nonNull(user.getDeptId())){
            Optional<InspectionDepartmentDO> deptOp = inspectionDepartmentDao.findById(user.getDeptId());
            if(deptOp.isPresent()){
                user.setDeptName(deptOp.get().getDeptName());
            }
        }
        user.setPassword(null);


        SysUserRoleDO userRoleQuery = new SysUserRoleDO();
        userRoleQuery.setUserId(user.getId());

        List<SysUserRoleDO> sysUserRoles = sysUserRoleDao.findAll(Example.of(userRoleQuery));

        if(!CollectionUtils.isEmpty(sysUserRoles)){
            user.setRoleIdList(sysUserRoles.stream().map(s -> s.getRoleId()).collect(Collectors.toList()));
        }

        return user;
    }

    @Override
    public Page<SysUserDO> pageUser(SysUserQueryDTO page) {

        Sort sort = SortHelper.buildSort(page);
        PageHelper check = PageHelper.check(page.getPageNo(), page.getPageSize());
        Pageable pageable = PageRequest.of(check.getOffset(), check.getPageSize(), sort);


        Page<SysUserDO> users =sysUserDao.findAll(buildSpecification(page), pageable);

        List<Long> deptIdList = new ArrayList<>();
        for (SysUserDO user : users) {
            if (Objects.nonNull(user.getDeptId())) {
                deptIdList.add(user.getDeptId());
            }
        }
        if (!CollectionUtils.isEmpty(deptIdList)) {
            List<InspectionDepartmentDO> deptList = inspectionDepartmentDao.findAllById(new HashSet<>(deptIdList));
            Map<Long, InspectionDepartmentDO> deptMap = deptList.stream().collect(Collectors.toMap(InspectionDepartmentDO::getId, InspectionDepartmentDO -> InspectionDepartmentDO));

            for (SysUserDO user : users) {
                if (Objects.nonNull(user.getDeptId())) {
                    InspectionDepartmentDO dept = deptMap.get(user.getDeptId());
                    if (Objects.nonNull(dept)) {
                        user.setDeptName(dept.getDeptName());
                    }
                }
            }
        }



        return users;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delUser(SysUserDTO dto) {
        AssertUtils.nonNull(dto.getId(), "系統用戶id不能為空！");

//        SysUserDO sysUser = AuthHolder.getSysUser();
//        Boolean isSysAdmin = false;
//        if ("00000".equalsIgnoreCase(sysUser.getUserCode())) {
//            isSysAdmin = true;
//        }
//        if (!isSysAdmin) {
//            throw new BusinessBaseException("沒有权限删除！");
//        }



        Optional<SysUserDO> sysUserOp = sysUserDao.findById(dto.getId());
        if (!sysUserOp.isPresent()) {
            throw new BusinessBaseException("用戶不存在");
        }

        SysUserDO userUpdate = sysUserOp.get();
        
        //超级管理员不允许删除
        if ("00000".equals(userUpdate.getUserCode())) {
            throw new BusinessBaseException("不允许删除超级管理员");
        }
        userUpdate.setIsDel(1);
        sysUserDao.saveAndFlush(userUpdate);
        //不删除用户和角色的关联
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelUser(SysUserDTO dto) {
//        SysUserDO sysUser = AuthHolder.getSysUser();
//        Boolean isSysAdmin = false;
//        if ("00000".equalsIgnoreCase(sysUser.getUserCode())) {
//            isSysAdmin = true;
//        }
//        if (!isSysAdmin) {
//            throw new BusinessBaseException("沒有权限删除！");
//        }

        List<SysUserDO> users = sysUserDao.findAllById(dto.getIdList());
        if(CollectionUtils.isEmpty(users)){
            throw new BusinessBaseException("用戶不存在");
        }

        for (SysUserDO user : users) {
            user.setIsDel(1);
            //超级管理员不允许删除
            if ("00000".equals(user.getUserCode())) {
                throw new BusinessBaseException("不允许删除超级管理员");
            }
            sysUserDao.saveAndFlush(user);
        }



    }

    @Override
    public void exportSysUser(SysUserQueryDTO query, HttpServletResponse response) {
        List<SysUserDO> users = sysUserDao.findAll(buildSpecification(query));

        List<Long> deptIdList = new ArrayList<>();
        for (SysUserDO user : users) {
            if (Objects.nonNull(user.getDeptId())) {
                deptIdList.add(user.getDeptId());
            }
        }
        if (!CollectionUtils.isEmpty(deptIdList)) {
            List<InspectionDepartmentDO> deptList = inspectionDepartmentDao.findAllById(new HashSet<>(deptIdList));
            Map<Long, InspectionDepartmentDO> deptMap = deptList.stream().collect(Collectors.toMap(InspectionDepartmentDO::getId, InspectionDepartmentDO -> InspectionDepartmentDO));

            for (SysUserDO user : users) {
                if (Objects.nonNull(user.getDeptId())) {
                    InspectionDepartmentDO dept = deptMap.get(user.getDeptId());
                    if (Objects.nonNull(dept)) {
                        user.setDeptName(dept.getDeptName());
                    }
                }
            }
        }

        List<SysUserExcelVO> vos = new ArrayList<>();

        for (SysUserDO user : users) {
            SysUserExcelVO vo = new SysUserExcelVO();
            BeanUtils.copyProperties(user, vo);
            vo.setUserStatusStr(UserStatusEnum.get(user.getUserStatus()).getMsg());
            vos.add(vo);
        }

        ArrayList<KeyValuePair> pairs = new ArrayList<>();
        pairs.add(KeyValuePair.builder().key("id").value("ID").build());
        pairs.add(KeyValuePair.builder().key("userCode").value("用户编码").build());
        pairs.add(KeyValuePair.builder().key("userName").value("用户名").build());
        pairs.add(KeyValuePair.builder().key("mobile").value("手机号").build());
        pairs.add(KeyValuePair.builder().key("realName").value("真名").build());
        pairs.add(KeyValuePair.builder().key("workPhone").value("工作手机号").build());
        pairs.add(KeyValuePair.builder().key("email").value("邮箱").build());
        pairs.add(KeyValuePair.builder().key("userStatusStr").value("用户状态").build());

       // pairs.add(KeyValuePair.builder().key("deptId").value("部门ID").build());
        pairs.add(KeyValuePair.builder().key("deptName").value("部门名称").build());
        pairs.add(KeyValuePair.builder().key("dateCreate").value("创建时间").build());

        ExcelUtils.export("用户导出",vos,pairs,response);



    }


    protected Specification<SysUserDO> buildSpecification(SysUserQueryDTO query) {
        return (Specification<SysUserDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.equal(root.get("isDel"),0));
            if (!StringUtils.isEmpty(query.getDeptId())) {
                predicates.add(criteriaBuilder.equal(root.get("deptId"), query.getDeptId()));
            }

            if (!StringUtils.isEmpty(query.getUserCode())) {
                predicates.add(criteriaBuilder.like(root.get("userCode"), "%"+query.getUserCode()+"%"));
            }

            if (!StringUtils.isEmpty(query.getUserName())) {
                predicates.add(criteriaBuilder.like(root.get("userName"), "%"+query.getUserName()+"%"));
            }

            if (!StringUtils.isEmpty(query.getMobile())) {
                predicates.add(criteriaBuilder.like(root.get("mobile"), "%"+query.getMobile()+"%"));
            }

            if (!StringUtils.isEmpty(query.getRealName())) {
                predicates.add(criteriaBuilder.like(root.get("realName"), "%"+query.getRealName()+"%"));
            }

            if (!StringUtils.isEmpty(query.getWorkPhone())) {
                predicates.add(criteriaBuilder.like(root.get("workPhone"), "%"+query.getWorkPhone()+"%"));
            }
            if (!StringUtils.isEmpty(query.getUserStatus())) {
                predicates.add(criteriaBuilder.equal(root.get("userStatus"), query.getUserStatus()));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    }





}
